package classfile

import (
	"fmt"
	. "jvm/typedef"
)

type ClassFile struct {
	minorVersion U2           //次版本号
	majorVersion U2           //主版本号
	constantPool ConstantPool //常量池
	accessFlags  U2
	thisClass    U2
	superClass   U2
	interfaces   []U2
	fields       []Field
	methods      []Method
	attributes   []Attribute
}

// public
func ParseBytecode(bytecode []U1) (classFile *ClassFile, err error) {
	defer func() {
		if r := recover(); r != nil {
			var ok bool
			err, ok = r.(error)
			if !ok {
				err = fmt.Errorf("%v", r)
			}
		}
	}()
	classFile = &ClassFile{}
	reader := newBytecodeReader(bytecode)

	classFile.parseAndCheckMagic(reader)
	classFile.parseAndCheckVersion(reader)
	classFile.parseConstantPool(reader)
	classFile.parseAccessFlags(reader)
	classFile.parseThisClass(reader)
	classFile.parseSuperClasss(reader)
	classFile.parseInterfaces(reader)
	classFile.parseFields(reader)
	classFile.parseMethods(reader)
	classFile.parseAttributes(reader)

	return
}
func (self *ClassFile) ClassName() string {
	return self.constantPool.getConstantClass(self.thisClass).ClassName()
}
func (self *ClassFile) SuperClassName() string {
	if self.superClass != 0 {
		return self.constantPool.getConstantClass(self.superClass).ClassName()
	}
	return ""
}
func (self *ClassFile) InterfaceNames() []string {
	length := len(self.interfaces)
	names := make([]string, length)
	for i := 0; i < length; i++ {
		names[i] = self.constantPool.getConstantClass(self.interfaces[i]).ClassName()
	}
	return names
}

//****************************************************************
//private

func (self *ClassFile) parseAndCheckMagic(reader *BytecodeReader) {
	magic := reader.readU4()
	if magic != 0xcafebabe {
		panic("字节码格式错误:magic!")
	}
}
func (self *ClassFile) parseAndCheckVersion(reader *BytecodeReader) {
	self.minorVersion = reader.readU2()
	self.majorVersion = reader.readU2()

	switch self.majorVersion {
	case 45:
		return
	case 46, 47, 48, 49, 50, 51, 52:
		if self.minorVersion == 0 {
			return
		}
	}
	panic("不支持的字节码版本号")
}
func (self *ClassFile) parseConstantPool(reader *BytecodeReader) {
	self.constantPool = newConstantPool(reader)
}

func (self *ClassFile) parseAccessFlags(reader *BytecodeReader) {
	self.accessFlags = reader.readU2()
}

func (self *ClassFile) parseThisClass(reader *BytecodeReader) {
	self.thisClass = reader.readU2()
}

func (self *ClassFile) parseSuperClasss(reader *BytecodeReader) {
	self.superClass = reader.readU2()
}

func (self *ClassFile) parseInterfaces(reader *BytecodeReader) {
	interfacesCount := reader.readU2()
	for i := 0; i < int(interfacesCount); i++ {
		self.interfaces = append(self.interfaces, reader.readU2())
	}
}

func (self *ClassFile) parseFields(reader *BytecodeReader) {
	self.fields = newFields(reader, self.constantPool)
}
func (self *ClassFile) parseMethods(reader *BytecodeReader) {
	self.methods = newMethods(reader, self.constantPool)
}
func (self *ClassFile) parseAttributes(reader *BytecodeReader) {
	self.attributes = newAttributes(reader, &self.constantPool)
}

//****************************************************************
//getter

func (self *ClassFile) MinorVersion() U2 {
	return self.minorVersion
}
func (self *ClassFile) MajorVersion() U2 {
	return self.majorVersion
}
func (self *ClassFile) ConstantPool() ConstantPool {
	return self.constantPool
}
func (self *ClassFile) AccessFlags() U2 {
	return self.accessFlags
}
func (self *ClassFile) ThisClass() U2 {
	return self.thisClass
}
func (self *ClassFile) SuperClass() U2 {
	return self.superClass
}
func (self *ClassFile) Interfaces() []U2 {
	return self.interfaces
}

func (self *ClassFile) Fields() []Field {
	return self.fields
}
func (self *ClassFile) Methods() []Method {
	return self.methods
}
func (self *ClassFile) Attributes() []Attribute {
	return self.attributes
}

//****************************************************************
